%ifndef BOOT_PROTECTEDMODEUTILITY_RESOLVEELF32
%define BOOT_PROTECTEDMODEUTILITY_RESOLVEELF32
%include "Boot/ProtectedModeUtility/CopyMemory.asm"
; ResolveELF32(LPVOID lpBase)
%define lpBase dword [ebp + 8]
; ebx 存放 ELF32 格式文件调入内存后的起始地址
; ELF32 header (52 B)
; e_iden, 16 B, char array
%define e_ident (ebx + 0)
; e_type, 2 B
%define e_type word [ebx + 16]
; e_machine, 2 B
%define e_machine word [ebx + 18]
; e_version, 4 B
%define e_version dword [ebx + 20]
; e_entry, 4 B
%define e_entry dword [ebx + 24]
; e_phoff, 4 B 
; 程序头表偏移量，也即第一个程序头在文件中的偏移量
%define e_phoff dword [ebx + 28]
; e_shoff, 4 B
; 节头表起始位置
%define e_shoff dword [ebx + 32]
; e_flags, 4 B
%define e_flags dword [ebx + 36]
; e_ehsize, 2 B
%define e_ehsize word [ebx + 40]
; e_phentsize, 2 B
; 程序头表每个表项的大小，也即程序头的大小
%define e_phentsize word [ebx + 42]
; e_phnum, 2 B
; 程序头表中的表项数目，即程序头的数目
%define e_phnum word [ebx + 44]
; e_shentsize, 2 B
%define e_shentsize word [ebx + 46]
; e_shnum, 2 B
%define e_shnum word [ebx + 48]
; e_shstrndx
%define e_shstrndx word [ebx + 50]

; esi 设定为程序头表在整个 ELF32 文件中的偏移量后可用基址变址寻址定位程序头表中各个字段
; Program segment header (32 B)
; p_type, 4 B
%define p_type dword [ebx + esi + 0]
; p_offset, 4 B
%define p_offset dword [ebx + esi + 4]
; p_vaddr, 4 B
%define p_vaddr dword [ebx + esi + 8]
; p_paddr, 4 B dword [ebx + 在分页状态下该字段无意义]
%define p_paddr dword [ebx + esi + 12]
; p_filesz, 4 B
%define p_filesz dword [ebx + esi + 16]
; p_memsz, 4 B
%define p_memsz dword [ebx + esi + 20]
; p_flags, 4 B
%define p_flags dword [ebx + esi + 24]
; p_align, 4 B
%define p_align dword [ebx + esi + 28]
bits 32
Boot.ProtectedModeUtility.ResolveELF32:
    push ebp
    mov ebp, esp
    push esi
    push ebx
    mov ebx, lpBase ; ELF32 文件基址
    mov esi, e_phoff ; 程序头表在整个 ELF32 文件中的偏移量，也即第零个程序头的起始地址，每解析完一个程序头，esi 的值增加 e_phentsize
    movzx ecx, e_phnum ; 程序头的数目
Boot.ProtectedModeUtility.ResolveELF32.Loop:
    cmp p_type, 0
    je Boot.ProtectedModeUtility.ResolveELF32.Next
    push p_filesz ; dwLen
    ; eax 保存文件中段的起始地址
    mov eax, ebx ; ELF32 文件调入内存的基址
    add eax, p_offset ; 段的偏移量
    push eax ; lpSrc
    push p_vaddr ; lpDst
    call Boot.Memory.CopyMemory ; 重定位段到指定虚拟内存位置
    add esp, 4 * 3
Boot.ProtectedModeUtility.ResolveELF32.Next:
    movzx eax, e_phentsize
    add esi, eax ; 下一个程序头
    loop Boot.ProtectedModeUtility.ResolveELF32.Loop
Boot.ProtectedModeUtility.ResolveELF32.Return:
    mov eax, e_entry ; 程序入口虚拟地址（返回值）
    pop ebx
    pop esi
    mov esp, ebp
    pop ebp
    ret
%undef lpBase
%undef e_ident
%undef e_type
%undef e_machine
%undef e_version
%undef e_entry
%undef e_phoff
%undef e_shoff
%undef e_flags
%undef e_ehsize
%undef e_phentsize
%undef e_phnum
%undef e_shentsize
%undef e_shnum
%undef e_shstrndx
%undef p_type
%undef p_offset
%undef p_vaddr
%undef p_paddr
%undef p_filesz
%undef p_memsz
%undef p_flags
%undef p_aligns
%endif